<script setup lang="ts" name="AiFlow">
import { VueFlow, useVueFlow, type Connection, Panel, type Edge } from '@vue-flow/core';
import { MiniMap } from '@vue-flow/minimap';
import { Background } from '@vue-flow/background';
import { Controls } from '@vue-flow/controls';
import nodeMetadata from '@/components/nodes/index';
import Toolbar from '@/components/toolbar.vue'
import NodeTypesList from "@/components/nodetype_list.vue"
import NodeProperty from "@/components/node_property.vue"
import SettingDialog from "@/components/setting_dialog.vue"
import NameLabel from "@/components/name_label.vue"
import LoadFlowDialog from '@/components/loadflow_dialog.vue'
import { toSavedCondition, type FlowAPI, type FlowData, type FlowNode } from './types/types';
import { nanoid } from 'nanoid';
import type { NodeTemplate, NodeTypeKey } from './types/node_templates';
import { ref, markRaw, computed, type PropType, provide, onMounted } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';

const aiFlow = ref()
const isNodeTypeListVisible = ref(false)
const isSettingDialogVisible = ref(false)

const props = defineProps({
    api: {
        type: Object as PropType<FlowAPI>,
        required: true
    }
})

provide('flowAPI', props.api)

const emit = defineEmits(['update:id'])

const flowId = ref<number>(0)
const flowName = ref<string>("未命名流程")


const {
    addNodes,
    addEdges,
    setNodes,
    setEdges,
    project,
    nodes,
    edges,
    dimensions,
    getSelectedNodes,
} = useVueFlow()

const showNodeTypeList = () => {
    isNodeTypeListVisible.value = !isNodeTypeListVisible.value
}

const showSettingDialog = () => {
    isSettingDialogVisible.value = true
}

const saveSettings = () => {
    isSettingDialogVisible.value = false
}

const selectedNode = computed(() => {
    const selectedNodes = getSelectedNodes.value
    if (selectedNodes.length > 0) {
        return selectedNodes[0]
    }
    return null
})

const nodeTypes = Object.keys(nodeMetadata).reduce((types, key) => {
    const typeKey = key as NodeTypeKey
    if (nodeMetadata[typeKey].component) {
        types[typeKey] = markRaw(nodeMetadata[typeKey].component)
    }
    return types
}, {} as Record<string, any>)

function handleAddNode(nodeTemplate: NodeTemplate) {
    const id = nodeTemplate.type + "-" + nanoid()

    const canvasCenter = getCanvasCenter()
    addNodes({
        id: id,
        type: nodeTemplate.type,
        position: canvasCenter,
        data: {
            label: `Node ${id}`,
            typeName: nodeTemplate.name,
            icon: nodeTemplate.icon,
            propertyComponent: nodeTemplate.propertyComponent,
            ...nodeTemplate.defaultData,
        },
    })
}

function getCanvasCenter() {
    const width = dimensions.value?.width || 800
    const height = dimensions.value?.height || 600

    const centerX = width / 2
    const centerY = height / 2

    const canvasCenter = project({ x: centerX, y: centerY })
    return canvasCenter
}

const handleConnect = (connection: Connection) => {
    // 检查是否已存在相同的edge连接
    const isDuplicate = edges.value.some(edge =>
        edge.source === connection.source &&
        edge.target === connection.target &&
        edge.sourceHandle === connection.sourceHandle &&
        edge.targetHandle === connection.targetHandle
    );

    if (isDuplicate) {
        ElMessage.warning('不能添加重复连接');
        return;
    }

    const edgeId = "edge-" + nanoid()
    addEdges({
        id: edgeId,
        ...connection,
    })
}

function getCurrentFlow() {
    if (flowName.value === "") {
        ElMessage.error("请先填写流程名称")
        return null
    }
    const nodesData = nodes.value.map(node => {
        const typeKey = node.type as NodeTypeKey;
        const template = nodeMetadata[typeKey];
        const dataToSave: { [key: string]: any } = {};
        if (template && template.serializableFields) {
            template.serializableFields.forEach(field => {
                if (node.data[field] !== undefined) {
                    if (field == "conditions") {
                        dataToSave[field] = node.data[field].map(toSavedCondition)
                    } else {
                        dataToSave[field] = node.data[field];
                    }
                }
            });
        }

        return {
            id: node.id,
            type: node.type,
            position: node.position,
            data: dataToSave,
        };

    })

    if (nodesData.length <= 0) {
        ElMessage.warning('没有节点可保存');
        return null;
    }

    const edgesData = edges.value.map(edge => ({
        id: edge.id,
        source: edge.source,
        target: edge.target,
        sourceHandle: edge.sourceHandle,
        targetHandle: edge.targetHandle,
    }))
    const flowData = {
        id: flowId.value,
        name: flowName.value,
        data: {},
        nodes: nodesData,
        edges: edgesData
    }

    return flowData
}

function createFlow() {
    flowId.value = 0;
    flowName.value = '未命名流程';
    setNodes([]);
    setEdges([]);
}

const handleNewFlow = () => {
    const hasContent = nodes.value.length > 0 || edges.value.length > 0;

    if (!hasContent) {
        // 没有内容，直接新建
        createFlow();
        return;
    }

    // 有内容，提示用户
    ElMessageBox.confirm('当前流程有未保存的内容，是否保存或放弃？', '提示', {
        confirmButtonText: '保存并新建',
        cancelButtonText: '放弃并新建',
        distinguishCancelAndClose: true,
        type: 'warning',
        closeOnClickModal: false
    }).then(() => {
        // 用户点击 “保存并新建”
        const flowData = getCurrentFlow();
        if (flowData && props.api.saveFlow) {
            props.api.saveFlow(flowData).then((res) => {
                createFlow()
                ElMessage.success('已保存并新建');
            });
        } else {
            ElMessage.warning('无法保存，请先配置保存接口');
        }
    }).catch(action => {
        if (action === 'cancel') {
            // 用户点击 “放弃并新建”
            createFlow()
            ElMessage.info('已放弃更改并新建流程');
        } else if (action === 'close') {
            // 用户点击关闭（取消）
            ElMessage.info('操作已取消');
        }
    });
};

function saveFlow() {
    const flowData = getCurrentFlow()
    if (!flowData) {
        return
    }
    if (props.api.saveFlow) {
        props.api.saveFlow(flowData).then((res) => {
            flowId.value = res.data.id
            ElMessage.success("保存成功:" + res.data.id);
        }).catch(err => {
            ElMessage.error("保存失败:" + err.message);
        })
    } else {
        ElMessage.error("请设置保存接口");
    }
}

const isPlaying = ref(false)

function playFlow() {
    const flowData = getCurrentFlow()
    if (!flowData) {
        ElMessage.warning('当前没有有效工作流。');
        return
    }
    if (flowData.id === 0) {
        ElMessage.warning('工作流ID为空。');
        return
    }
    if (props.api.runFlow) {
        props.api.runFlow(flowData).then(res => {
            if (res.code == 200) {
                ElMessage.success("运行成功");
                isPlaying.value = true
            } else {
                ElMessage.error("运行失败")
            }
            
        }).catch(err => {
            ElMessage.error("运行失败");
        })

    } else {
        ElMessage.error("请配置运行接口");
    }
}

const closeChatDialog = () => {
    isPlaying.value = false
}

const showLoadDialog = ref(false)

const handleLoadFlow = async (id: string) => {
    if (props.api.getFlow) {
        props.api.getFlow({ id }).then(res => {
            if (res.code !== 200) {
                ElMessage.error("加载应用失败");
                return
            }
            loadFlowData(res.data)
        }).catch(err => {
            ElMessage.error("加载应用失败");
        })
    } else {
        ElMessage.error("请配置加载接口");
    }
}

function loadFlowData(data: any) {
    let flowData: FlowData;
    try {
        flowData = JSON.parse(data.Script);
    } catch (err) {
        ElMessage.error('流程数据解析失败');
        return;
    }

    var nodes: FlowNode[] = []
    // 添加节点
    flowData.nodes.forEach(node => {
        try {
            const nodeTemplate = nodeMetadata[node.type as NodeTypeKey]; // ✅ 正确声明 + 类型断言

            if (!nodeTemplate) {
                throw new Error(`找不到类型为 ${node.type} 的节点模板`);
            }

            node.data.icon = nodeTemplate.icon
            node.data.typeName = nodeTemplate.name
            node.data.propertyComponent = nodeTemplate.propertyComponent
            nodes.push(node);
        } catch (error) {
            console.error('添加节点失败:', error);
        }
    });

    var edges: Edge[] = []
    // 添加边（必须在节点之后）
    flowData.edges.forEach(edge => {
        edges.push({
            id: edge.id,
            source: edge.source,
            target: edge.target,
            sourceHandle: edge.sourceHandle,
            targetHandle: edge.targetHandle,
        });
    });

    // 设置流程名称
    flowName.value = data.Name;
    flowId.value = data.ID;

    // 清空当前画布
    setNodes(nodes);
    setEdges(edges);

    emit('update:id', flowData.id)
}

function loadFlow() {
    showLoadDialog.value = true
}

onMounted(() => {
    createFlow()
})
</script>

<template>
    <VueFlow :node-types="nodeTypes" ref="aiFlow" :defaultViewport="{ zoom: 1 }" :maxZoom="2" :minZoom="0.1"
        :class="[$attrs.class]" :selectNodesOnDrag="false" :multiSelectionActive="false" @connect="handleConnect">
        <Background />
        <Panel position="top-left" class="toollist-panel">
            <NameLabel v-model="flowName" />
            <Toolbar @show-node-type-list="showNodeTypeList" @save-flow="saveFlow" @show-setting="showSettingDialog"
                @playFlow="playFlow" @loadFlow="loadFlow" @createFlow="handleNewFlow" />
            <div class="sub-panel">
                <NodeTypesList v-show="isNodeTypeListVisible" @addNode="handleAddNode" :nodes="nodes" />
            </div>
        </Panel>
        <NodeProperty v-if="selectedNode" :node="selectedNode" />
        <MiniMap />
        <Controls position="bottom-left" />
        <SettingDialog v-model="isSettingDialogVisible" @confirm="saveSettings" />
        <LoadFlowDialog v-model="showLoadDialog" @load="handleLoadFlow" :api="props.api" />
    </VueFlow>
    <slot name="chat-dialog" v-if="isPlaying" :visible="isPlaying" :id="flowId" :on-close="closeChatDialog">
        <div style="
        position: fixed;
        top: 20px;
        right: 20px;
        z-index: 9999;
        background: red;
        color: white;
      ">
            默认插槽内容
        </div>
    </slot>
</template>

<style scoped>
.toollist-panel {
    padding: 5px;
    background-color: transparent;
    min-width: 280px;
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.flow-name-panel {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 8px 12px;
    background-color: #f5f7fa;
    border-bottom: 1px solid #e4e7ed;
}

.flow-name {
    font-size: 16px;
    font-weight: bold;
    color: #333;
}

.edit-name-button {
    padding: 4px 10px;
    font-size: 12px;
    background-color: #42b983;
    color: white;
    border: none;
    border-radius: 4px;
    cursor: pointer;
}

.edit-name-button:hover {
    background-color: #379c6f;
}
</style>
